#ifndef OPENHITLS_KAE_RSA_H
#define OPENHITLS_KAE_RSA_H

#include <bsl_err_internal.h>
#include <bsl_errno.h>
#include <bsl_params.h>
#include <crypt_algid.h>
#include <crypt_bn.h>
#include <crypt_errno.h>
#include <crypt_local_types.h>
#include <crypt_rsa.h>

#include <wd.h>
#include <wd_rsa.h>

#include "kaev1_memory.h"

extern KaeQueuePoolHead *gRsaNodePool;

#define KAE_RSA_MAX_MODULUS_BITS 4096
#define KAE_RSA_MAX_MODULUS_LEN  (KAE_RSA_MAX_MODULUS_BITS / 8)

#define PARAMISNULL(a) (a == NULL || a->value == NULL)
#define ROUND_UP(bits) ((((bits) + 1023) >> 10) << 10)

typedef struct RSA_Para {
    BN_BigNum *e; // Exponent Value -converted.Not in char
    uint32_t bits; // length in bits of modulus
    BN_BigNum *p; // prime factor p
    BN_BigNum *q; // prime factor q
} RSA_Para;

typedef struct {
    BN_BigNum *n; // pub key n needed for no padding
    BN_BigNum *d; // private key d needed for asn encoding
    BN_BigNum *p; // prime factor p
    BN_BigNum *q; // prime factor q
    BN_BigNum *dP; // exponent dP for CRT
    BN_BigNum *dQ; // exponent dQ for CRT
    BN_BigNum *qInv; // CRT coefficient qInv
    BN_BigNum *e; // public key e
} KAE_RSA_PrvKey;

typedef struct {
    BN_BigNum *n; // modulo Value - converted.Not in char
    BN_BigNum *e; // Exponent Value -converted.Not in char

    // Montgomery pre-calculation cache
    BN_Mont *mont;
} KAE_RSA_PubKey;

typedef enum {
    EMSA_PKCSV15 = 1,
    EMSA_PSS,
    RSAES_OAEP,
    RSAES_PKCSV15,
    RSA_NO_PAD,
    RSAES_PKCSV15_TLS,
} RSA_PadType;

typedef struct {
    CRYPT_MD_AlgId mdId; /**< ID of the hash algorithm during pkcsv15 padding */
} RSA_PkcsV15Para;

typedef struct {
    RSA_PadType type; /**< padding id */
    union {
        RSA_PkcsV15Para pkcsv15; /**< pkcsv15 padding mode */
        RSA_PadingPara pss; /**< pss padding mode */
        RSA_PadingPara oaep; /**< oaep padding mode */
    } para; /**< padding mode combination, including pss and pkcsv15 */
    CRYPT_Data salt; // Used for the KAT test.
} RSAPad;

typedef struct KAE_RSA_Ctx {
    struct wd_queue *queue;
    struct wd_queue_mempool *pool;
    struct wcrypto_rsa_ctx_setup setup;
    struct wcrypto_rsa_op_data opData;
    void *rsaCtx;
    KaeQueueDataEntry *entry;
    struct wcrypto_rsa_pubkey *pubKey;
    struct wcrypto_rsa_prikey *prvKey;
    RSA_Para *para;
    KAE_RSA_PubKey *kPubKey;
    KAE_RSA_PrvKey *kPrvKey;
    RSAPad pad;
    CRYPT_Data label;
    uint32_t flags;
} KAE_RSA_Ctx;

int WdRsaInitQnodePool(void);

int WdRsaDestroyQnodePool(void);

KAE_RSA_Ctx *KAE_RSA_NewCtx(void);

int32_t KAE_RSA_SetPara(KAE_RSA_Ctx *ctx, const BSL_Param *para);

int32_t KAE_RSA_GenKey(KAE_RSA_Ctx *ctx);

int32_t KAE_RSA_SetPrv(KAE_RSA_Ctx *ctx, const BSL_Param *para);

int32_t KAE_RSA_SetPub(KAE_RSA_Ctx *ctx, const BSL_Param *para);

int32_t KAE_RSA_GetPrv(const KAE_RSA_Ctx *ctx, BSL_Param *para);

int32_t KAE_RSA_GetPub(const KAE_RSA_Ctx *ctx, BSL_Param *para);

KAE_RSA_Ctx *KAE_RSA_DupCtx(KAE_RSA_Ctx *ctx);

int32_t KAE_RSA_Cmp(const KAE_RSA_Ctx *a, const KAE_RSA_Ctx *b);

int32_t KAE_RSA_Ctrl(KAE_RSA_Ctx *ctx, int32_t opt, void *val, uint32_t len);

int32_t KAE_RSA_SignData(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *sign, uint32_t *signLen);

int32_t KAE_RSA_VerifyData(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *sign, uint32_t signLen);

int32_t KAE_RSA_Sign(KAE_RSA_Ctx *ctx, int32_t algId, const uint8_t *data, uint32_t dataLen, uint8_t *sign,
                     uint32_t *signLen);

int32_t KAE_RSA_Verify(KAE_RSA_Ctx *ctx, int32_t algId, const uint8_t *data, uint32_t dataLen, uint8_t *sign,
                       uint32_t signLen);

int32_t KAE_RSA_Encrypt(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *out, uint32_t *outLen);

int32_t KAE_RSA_Decrypt(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *out, uint32_t *outLen);

int32_t KAE_RSA_Blind(KAE_RSA_Ctx *ctx, int32_t algId, const uint8_t *input, uint32_t inputLen, uint8_t *out,
                      uint32_t *outLen);

int32_t KAE_RSA_UnBlind(const KAE_RSA_Ctx *ctx, const uint8_t *input, uint32_t inputLen, uint8_t *out,
                        uint32_t *outLen);

void KAE_RSA_Free(KAE_RSA_Ctx *ctx);

#endif